package com.gegewa.topic.jdata.sameagain;

import lombok.Data;

import java.text.SimpleDateFormat;
import java.util.*;

@Data
public class ForecastPurchaseHandler {

    private Map<String, Set<String>> historyMap;

    public ForecastPurchaseHandler(Map<String, Set<String>> historyMap) {
        this.historyMap = historyMap;
    }

    public List<String[]> getForecastPurchaseResult() {
        List<String> atLeastTwicePurchaseHistoryUserIdList = getAtLeastTwicePurchaseHistoryUserIdList();
        Map<String, Map<String,Integer>> forecastMap = getAgainPurchaseData(atLeastTwicePurchaseHistoryUserIdList);
//        if (forecastMap.size() < 12000) {
//            addTo12000(forecastMap);
//        }
        Map<Integer, Integer> weightMap = keepMaxWeightSkuId(forecastMap);
//        List<String[]> forecastList = get12000User(forecastMap);
        List<String[]> forecastList = get12000UserMap(forecastMap, weightMap);
        return forecastList;
    }

    public List<String> getAtLeastTwicePurchaseHistoryUserIdList() {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String nowData = simpleDateFormat.format(new Date());
        System.out.println("获取两次或以上购物记录开始时间：" + nowData);
        List<String> atLeastTwicePurchaseHistoryUserIdList = new ArrayList<>(35000);
        for (Map.Entry<String, Set<String>> entry : historyMap.entrySet()) {
            if (entry.getValue().size() > 1) {
                atLeastTwicePurchaseHistoryUserIdList.add(entry.getKey());
            }
        }
        nowData = simpleDateFormat.format(new Date());
        System.out.println("获取两次或以上购物记录结束时间：" + nowData + ",数量为：" + atLeastTwicePurchaseHistoryUserIdList.size());
        return atLeastTwicePurchaseHistoryUserIdList;
    }

    public Map<String, Map<String,Integer>> getAgainPurchaseData(List<String> atLeastTwicePurchaseHistoryUserIdList) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String nowData = simpleDateFormat.format(new Date());
        System.out.println("获取再次购物数据开始时间：" + nowData);
        Map<String, Map<String,Integer>> forecastMap = new HashMap<>(50000);
        int firstLoopIndex = 0;
        for (int i = 0, iCount = atLeastTwicePurchaseHistoryUserIdList.size(); i < iCount; i++) {
            if (++firstLoopIndex % 1000 == 1) {
                nowData = simpleDateFormat.format(new Date());
                System.out.println("firstLoopIndex=" + firstLoopIndex + "，forecastMap.size()=" + forecastMap.size() + "，时间：" + nowData);
            }
            for (Map.Entry<String, Set<String>> entry : historyMap.entrySet()) {
                if (hasSameProduct(historyMap.get(atLeastTwicePurchaseHistoryUserIdList.get(i)), entry.getValue())) {
                    Set<String> basicSkuIdSet = historyMap.get(atLeastTwicePurchaseHistoryUserIdList.get(i));
                    for (String skuId : basicSkuIdSet) {
                        if (!entry.getValue().contains(skuId)) {
                            if (forecastMap.containsKey(entry.getKey())) {
                                Map<String, Integer> map = forecastMap.get(entry.getKey());
                                if (map.containsKey(skuId)) {
                                    map.put(skuId, map.get(skuId) + 1);
                                } else {
                                    map.put(skuId, 1);
                                }
                                forecastMap.put(entry.getKey(), map);
                            } else {
                                Map<String, Integer> map = new HashMap<>();
                                map.put(skuId, 1);
                                forecastMap.put(entry.getKey(), map);
                            }
                        }
                    }
                }
            }
        }
        nowData = simpleDateFormat.format(new Date());
        System.out.println("获取再次购物数据结束时间：" + nowData + "，forecastMap.size()=" + forecastMap.size());
        return forecastMap;
    }

    private boolean hasSameProduct(Set<String> basicSkuIdSet, Set<String> targetSkuIdSet) {
        for (String skuId : basicSkuIdSet) {
            if (targetSkuIdSet.contains(skuId)) {
                return true;
            }
        }
        return false;
    }

    private void addTo12000(Map<String, String> forecastMap) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String nowData = simpleDateFormat.format(new Date());
        System.out.println("购物数据添加到12000开始时间：" + nowData + "，forecastMap.size()=" + forecastMap.size());
        for (int i = forecastMap.size(); i < 12000; i++) {
            Set<String> userIdSet = historyMap.keySet();
            boolean hasFind = false;
            for (String userId : userIdSet) {
                if (!forecastMap.containsKey(userId)) {
                    hasFind = true;
                    for (String skuId : historyMap.get(userId)) {
                        forecastMap.put(userId, skuId);
                        break;
                    }
                }
                if (hasFind) {
                    break;
                }
            }
        }
        nowData = simpleDateFormat.format(new Date());
        System.out.println("购物数据添加到12000结束时间：" + nowData+ "，forecastMap.size()=" + forecastMap.size());
    }

    private Map<Integer, Integer> keepMaxWeightSkuId(Map<String, Map<String,Integer>> forecastMap) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String nowData = simpleDateFormat.format(new Date());
        System.out.println("保留最大权重SkuId开始时间：" + nowData + "，forecastMap.size()=" + forecastMap.size());
        Map<Integer, Integer> weightMap = new HashMap<>(1000);
        for (Map.Entry<String, Map<String, Integer>> entry : forecastMap.entrySet()) {
            if (entry.getValue().size() > 1) {
                String maxWeightSkuId = "";
                Map<String, Integer> skuWeightMap = entry.getValue();
                for (Map.Entry<String, Integer> item : skuWeightMap.entrySet()) {
                    if ("".equals(maxWeightSkuId)) {
                        maxWeightSkuId = item.getKey();
                    } else if (skuWeightMap.get(maxWeightSkuId) < item.getValue()) {
                        maxWeightSkuId = item.getKey();
                    }
                }
                int weight = skuWeightMap.get(maxWeightSkuId);
                skuWeightMap.clear();
                skuWeightMap.put(maxWeightSkuId, weight);
            }
            getWeight(entry.getValue(), weightMap);
        }
        nowData = simpleDateFormat.format(new Date());
        System.out.println("保留最大权重SkuId结束时间：" + nowData + "，weightMap.size()=" + weightMap.size());
        return weightMap;
    }

    private List<String[]> get12000UserMap(Map<String, Map<String,Integer>> forecastMap, Map<Integer, Integer> weightMap) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String nowData = simpleDateFormat.format(new Date());
        System.out.println("获取12000购物数据开始时间：" + nowData + "，forecastMap.size()=" + forecastMap.size());
        List<String[]> forecastList = new ArrayList<>(12000);

        Integer[] minWeight = minWeight(weightMap);
        int weightUp = minWeight[0];
        int weightDown = minWeight[1];
        int weightDownCount = minWeight[2];

        int currentWeightDownCount = 0;
        for (Map.Entry<String, Map<String,Integer>> entry : forecastMap.entrySet()) {
            for (Map.Entry<String, Integer> weightEntry : entry.getValue().entrySet()) {
                if (weightEntry.getValue() >= weightUp) {
                    forecastList.add(new String[] {entry.getKey(), weightEntry.getKey()});
                } else if (weightEntry.getValue() >= weightDown && ++currentWeightDownCount <= weightDownCount) {
                    forecastList.add(new String[] {entry.getKey(), weightEntry.getKey()});
                }
            }
        }
        nowData = simpleDateFormat.format(new Date());
        System.out.println("获取12000购物数据结束时间：" + nowData + "，forecastList.size()=" + forecastList.size());
        return forecastList;
    }

    private Integer[] minWeight(Map<Integer, Integer> weightMap) {
        List<Integer> weightList = new ArrayList<>(1000);
        for (Map.Entry<Integer, Integer> entry : weightMap.entrySet()) {
            weightList.add(entry.getKey());
        }
        Collections.sort(weightList);
        int count = 0;
        int currentIndex = weightList.size() - 1;
        for (; currentIndex >= 0; currentIndex--) {
            if (count + weightMap.get(weightList.get(currentIndex)) > 12000) {
                break;
            }
            count += weightMap.get(weightList.get(currentIndex));
        }
        Integer[] minWeight = new Integer[3];
        minWeight[0] = weightList.get(currentIndex + 1);
        minWeight[1] = weightList.get(currentIndex);
        minWeight[2] = 12000 - count;
        return minWeight;
    }

    private List<String[]> get12000User(Map<String, String> forecastMap) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String nowData = simpleDateFormat.format(new Date());
        System.out.println("获取12000购物数据开始时间：" + nowData + "，forecastMap.size()=" + forecastMap.size());
        List<String[]> forecastList = new ArrayList<>();
        int count = -1;
        for (Map.Entry<String, String> entry : forecastMap.entrySet()) {
            if (++count == 12000) {
                break;
            }
            forecastList.add(new String[] {entry.getKey(), entry.getValue()});
        }
        nowData = simpleDateFormat.format(new Date());
        System.out.println("获取12000购物数据开始时间：" + nowData + "，forecastList.size()=" + forecastList.size());
        return forecastList;
    }

    private void getWeight(Map<String, Integer> skuWeightMap, Map<Integer, Integer> weightMap) {
        for (Integer skuWeight : skuWeightMap.values()) {
            if (weightMap.containsKey(skuWeight)) {
                weightMap.put(skuWeight, weightMap.get(skuWeight) + 1);
            } else {
                weightMap.put(skuWeight, 1);
            }
        }
    }

}
